package cn.virens.server.aio;

import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.virens.app.AppConfig;
import cn.virens.app.cmpt.Component;
import cn.virens.common.utils.common.CloseableUtil;
import cn.virens.server.aio.channel.AioChannel;
import cn.virens.server.aio.channel.AioChannelSimple;
import cn.virens.server.aio.handler.PacketHandler;
import cn.virens.server.aio.listener.AioDataDecoder;
import cn.virens.server.aio.listener.AioDataEncoder;
import cn.virens.server.aio.listener.AioDataErrorListener;
import cn.virens.server.aio.listener.AioDataReadListener;
import cn.virens.server.aio.listener.AioDataWriteListener;
import cn.virens.server.aio.listener.AioStateCloseableListener;
import cn.virens.server.aio.listener.AioStateConnectedListener;
import cn.virens.server.aio.listener.AioStateExceptionListener;
import cn.virens.server.aio.packet.AioWritePacket;

public class AioServerManageImpl implements AioServerManage, Component {
	private final Logger logger = LoggerFactory.getLogger(getClass());

	protected final List<PacketHandler> handlerPool = new ArrayList<>();

	protected AsynchronousServerSocketChannel serverSocketChannel;
	protected AsynchronousSocketAcceptHandler socketAcceptHandler;

	protected AsynchronousChannelGroup channelGroup = null;

	protected ExecutorService groupExecutor = null;
	protected ExecutorService wokerExecutor = null;

	// 数据解码/编码器
	protected AioDataDecoder aioDataDecoder;
	protected AioDataEncoder aioDataEncoder;

	// 数据操作监听事件
	protected AioDataReadListener aioDataReadListener;
	protected AioDataWriteListener aioDataWriteListener;
	protected AioDataErrorListener aioDataErrorListener;

	// 连接状态监听事件
	protected AioStateConnectedListener aioStateConnectedListener;
	protected AioStateCloseableListener aioStateCloseableListener;
	protected AioStateExceptionListener aioStateExceptionListener;

	private String host;
	private Integer port;

	private boolean isWaitStop;

	@Override
	public void initialize(AppConfig config) throws Exception {
		this.groupExecutor = Executors.newCachedThreadPool();
		this.wokerExecutor = Executors.newCachedThreadPool();

		this.channelGroup = AsynchronousChannelGroup.withThreadPool(groupExecutor);
		this.serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);
		this.socketAcceptHandler = AsynchronousSocketAcceptHandler.newInstance(this);

		this.serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
		this.serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);

		this.port = config.getInteger("aio.port");
		this.host = config.getString("aio.host");

		if (host == null || host.isEmpty()) {
			this.serverSocketChannel.bind(new InetSocketAddress(port), 0);
			this.serverSocketChannel.accept(null, socketAcceptHandler);
		} else {
			this.serverSocketChannel.bind(new InetSocketAddress(host, port), 0);
			this.serverSocketChannel.accept(null, socketAcceptHandler);
		}

		this.logger.debug("AIO Server Start...");
		this.logger.debug("AIO Server Config.post:" + port);
		this.logger.debug("AIO Server Config.host:" + host);
	}

	@Override
	public boolean isWaitStop() {
		return isWaitStop;
	}

	@Override
	public String getHost() {
		return host;
	}

	@Override
	public Integer getPort() {
		return port;
	}

	@Override
	public void send(AioChannel aioChannel, AioWritePacket packet) {
		AioChannelSimple aioChannelSimple = (AioChannelSimple) aioChannel;

		// 获取对应的连接通道的写操作线程，并放进去执行发送
		aioChannelSimple.getChannelWriteRunnable().offer(packet);
		aioChannelSimple.getChannelWriteRunnable().execute();
	}

	@Override
	public void send(String uid, AioWritePacket packet) {
		this.send(getChannel(uid), packet);
	}

	@Override
	public void bindUid(AioChannel aioChannel, String uid) {
		this.socketAcceptHandler.bindUid(aioChannel, uid);
	}

	@Override
	public void unbindUid(AioChannel aioChannel) {
		this.socketAcceptHandler.unbindUid(aioChannel);
	}

	@Override
	public AioChannel getChannel(String uid) {
		return socketAcceptHandler.getChannel(uid);
	}

	@Override
	public Set<AioChannel> getChannelAll() {
		return socketAcceptHandler.getChannelAll();
	}

	@Override
	public Set<String> getChannelKeys() {
		return socketAcceptHandler.getChannelKeys();
	}

	/** 添加 数据包解析器 */
	public final void addHandler(PacketHandler handler) {
		synchronized (handlerPool) {
			this.handlerPool.add(handler);
		}
	}

	public void setAioDataDecoder(AioDataDecoder aioDataDecoder) {
		this.aioDataDecoder = aioDataDecoder;
	}

	public void setAioDataEncoder(AioDataEncoder aioDataEncoder) {
		this.aioDataEncoder = aioDataEncoder;
	}

	public void setAioDataReadListener(AioDataReadListener aioDataReadListener) {
		this.aioDataReadListener = aioDataReadListener;
	}

	public void setAioDataWriteListener(AioDataWriteListener aioDataWriteListener) {
		this.aioDataWriteListener = aioDataWriteListener;
	}

	public void setAioDataErrorListener(AioDataErrorListener aioDataErrorListener) {
		this.aioDataErrorListener = aioDataErrorListener;
	}

	public void setAioStateConnectedListener(AioStateConnectedListener aioStateConnectedListener) {
		this.aioStateConnectedListener = aioStateConnectedListener;
	}

	public void setAioStateCloseableListener(AioStateCloseableListener aioStateCloseableListener) {
		this.aioStateCloseableListener = aioStateCloseableListener;
	}

	public void setAioStateExceptionListener(AioStateExceptionListener aioStateExceptionListener) {
		this.aioStateExceptionListener = aioStateExceptionListener;
	}

	@Override
	public void destroy() throws Exception {
		CloseableUtil.close(serverSocketChannel);
		CloseableUtil.close(socketAcceptHandler);
	}
}
